/*
 * Copyright (c) 2018-2024 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "hash.h"
#include "common.h"
#include "resreq.h"
#include "lib.h"

#define KEY_DURATION    1
#define KEY_HOSTS       2
#define KEY_PTILE       3
#define KEY_DECAY       4
#define KEY_NUMA        5
#define KEY_SOCKET      6
#define KEY_CORE        7
#define KEY_THREAD      8
#define KEY_CPUBIND     9
#define KEY_MEMBIND     10
#define KEY_DISTRIBUTE  11
#define NUM_KEYS        12

#define IS_VALID_OTHER(s) ((s) == '_'|| (s) == '~')

struct sections {
    char *select;
    char *order;
    char *rusage;
    char *filter;
    char *span;
    char *affinity;
};

#define SELECT_SECT     0
#define ORDER_SECT      1
#define RUSAGE_SECT     2
#define FILTER_SECT     3
#define SPAN_SECT       4
#define AFFINITY_SECT   5
#define NUMSECTION      6
const char *keywords[]= {
    "select",
    "order",
    "rusage",
    "filter",
    "span",
    "affinity"
};

static HASH_TABLE_T *shashResource;
static HASH_TABLE_T *shashKeyword;
static char *sstrRequirement;
static unsigned int sintLenReq;

static int split_sections(char *, struct sections *);

static void free_resrsv(void *);
static int set_default_req(struct requirement *, struct quickpoolInfo *, int);
static int set_select_req(char *, struct quickpoolInfo *, int, struct requirement *);
static int set_resusage_req(char *, struct quickpoolInfo *, struct requirement *);
static int set_order_req(char *, struct quickpoolInfo *, struct requirement *);
static int set_filter_req(char *, struct quickpoolInfo *, struct requirement *);
static int set_span_req(char *, struct requirement *);
static int set_affinity_req(char *, struct requirement *);

static int transfer_select(char *, struct quickpoolInfo *, struct requirement *);
static int key_index (char *);

#define ALLOC_STRING(buffer, buffer_len, req_len) {     \
        if (buffer == NULL || buffer_len < req_len) {   \
            FREEUP(buffer);                             \
            buffer = (char *)calloc(req_len, sizeof(char));	\
            buffer_len = req_len;                       \
        }                                               \
    }

/**
 * @brief       Initialize resource table and key table for evaluting resource requirement.
 *
 * @param[in]   info          #1: quickpool resource information
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, not enough memory
 *
 * @note        All the resources are put into resource hash table.
 *              All requirement keywords are put into key hash table.
 */
int
initialize_parser_hash(struct quickpoolInfo *info)
{
    unsigned int           i;
    unsigned int          *indx;

    shashResource = gf_hash_make(info->num_resources);
    if (NULL == shashResource) {
        return PARSE_ERROR_MEMORY;
    }

    for (i = 0; i < info->num_resources; i++) {
        indx = (unsigned int *)calloc(1, sizeof(unsigned int));
        if (NULL == indx) {
            return PARSE_ERROR_MEMORY;
        }

        *indx = i;
        gf_hash_install(shashResource, info->resource_table[i].name, (void *)indx);
    }

    indx = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == indx) {
        return PARSE_ERROR_MEMORY;
    }
    *indx = SWP;
    gf_hash_install(shashResource, "swap", (void *)indx);

    indx = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == indx) {
        return PARSE_ERROR_MEMORY;
    }
    *indx = R5M;
    gf_hash_install(shashResource, "cpu", (void *)indx);

    shashKeyword = gf_hash_make(NUM_KEYS);
    if (NULL == shashKeyword) {
        return PARSE_ERROR_MEMORY;
    }

    unsigned int *key;
    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_DURATION;
    gf_hash_install(shashKeyword, "duration", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_DECAY;
    gf_hash_install(shashKeyword, "decay", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_HOSTS;
    gf_hash_install(shashKeyword, "hosts", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_PTILE;
    gf_hash_install(shashKeyword, "ptile", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }    
    *key = KEY_NUMA;
    gf_hash_install(shashKeyword, "numa", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        abort();
    }    
    *key = KEY_SOCKET;
    gf_hash_install(shashKeyword, "socket", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }    
    *key = KEY_CORE;
    gf_hash_install(shashKeyword, "core", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_THREAD;
    gf_hash_install(shashKeyword, "thread", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_CPUBIND;
    gf_hash_install(shashKeyword, "cpubind", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_MEMBIND;
    gf_hash_install(shashKeyword, "membind", (void *)key);

    key = (unsigned int *)calloc(1, sizeof(unsigned int));
    if (NULL == key) {
        return PARSE_ERROR_MEMORY;
    }
    *key = KEY_DISTRIBUTE;
    gf_hash_install(shashKeyword, "distribute", (void *)key);
    
    return 0;
} // end function initialize_parser_hash

/**
 * @brief       Get resouce index from resource hash table.
 *
 * @param[in]   res           #1: resource name
 *
 * @retval      >= 0          #1: succeed, index of the resource
 * @retval      -1            #2: failed, resource not found
 */
int
get_resource_index_fromhash(const char *res)
{
    unsigned int *indx;

    indx = (unsigned int *)gf_hash_find(shashResource, res);
    if (NULL == indx) {
        return -1;
    }

    return (int)(*indx);
} // end function get_resource_index_fromhash

/**
 * @brief       Parse job requirement string into sections and set
 *              requirement of each section.
 *
 * @param[in]   strreq        #1: job requirement string
 * @param[in]   info          #2: cluster resource table
 * @param[in]   options       #3: options for parsing the string
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, requirement string has syntax error
 */
int
set_requirement(char *strreq, struct quickpoolInfo *info, int options,
                struct requirement *req)
{
    if (NULL == strreq) {
        return PARSE_BAD_EXP;
    }

    ALLOC_STRING(req->select, req->sizeof_select,
                 MAX(3*strlen(strreq) + 1, PATH_MAX + MAXNAMELEN));
    if (NULL == req->select) {
        return PARSE_ERROR_MEMORY;
    }

    int i;
    char *sectionArray[NUMSECTION];
    for (i=0; i<NUMSECTION; i++) {
        sectionArray[i] = NULL;
    }

    if (sintLenReq < strlen(strreq)) {
        FREEUP(sstrRequirement);
        sstrRequirement = copy_string(strreq);
        sintLenReq = strlen(strreq);
    } else {
        strcpy(sstrRequirement, strreq);
    }

    for (i=0; i<NUMSECTION; i++) {

        char *sp;
        sp = sstrRequirement;

        char *strSec;
        while (NULL != (strSec=strstr(sp, keywords[i]))) {

            if ('[' == *(strSec + strlen(keywords[i]))) {
                sectionArray[i] = strSec;
                break;
            } else {
                sp = strSec + strlen(keywords[i]);
            }
        }
    }

    for (i=0; i<NUMSECTION; i++) {

        if (NULL == sectionArray[i]) {

            if (i == SELECT_SECT) {
                sectionArray[i] = sstrRequirement;
            } else {
                sectionArray[i] = (sstrRequirement+sintLenReq);
            }

            continue;
        }

        *sectionArray[i] = '\0';
        sectionArray[i] += strlen(keywords[i]);
        if ('[' != *sectionArray[i]) {
            return PARSE_BAD_EXP;
        }

        sectionArray[i]++;

        char *sp;
        sp = sectionArray[i];
        while (']' != *sp && '\0' != *sp) {
            sp++;
        }

        if (']' != *sp) {
            return PARSE_BAD_EXP;
        }

        *sp  = '\0';
    }

    for (i=0; i<NUMSECTION; i++) {
        strip_spaces(sectionArray[i], FALSE);
    }

    struct sections reqSect;
    reqSect.select = sectionArray[SELECT_SECT];
    reqSect.order  = sectionArray[ORDER_SECT];
    reqSect.rusage = sectionArray[RUSAGE_SECT];
    reqSect.filter = sectionArray[FILTER_SECT];
    reqSect.span   = sectionArray[SPAN_SECT];
    reqSect.affinity = sectionArray[AFFINITY_SECT];

    int ret=0;
    ret = set_default_req(req, info, options);
    if (0 > ret) {
        return ret;
    }

    if (options & REQ_SELECT) {

        ret = set_select_req(reqSect.select, info, options, req);
        if (0 != ret) {
            return ret;
        }
    }

    if (options & REQ_ORDER) {
        ret = set_order_req(reqSect.order, info, req);
        if (0 != ret) {
            return ret;
        }
    }

    if (options & REQ_RUSAGE) {
        ret = set_resusage_req(reqSect.rusage, info, req);
        if (0 != ret) {
            return ret;
        }
    }

    if (options & REQ_FILTER) {
        ret = set_filter_req(reqSect.filter, info, req);
        if (0 != ret) {
            return ret;
        }
    }

    if (options & REQ_SPAN) {
        ret = set_span_req(reqSect.span, req);
        if (0 != ret) {
            return ret;
        }
    }
    
    if (options & REQ_AFFINITY) {
        ret = set_affinity_req(reqSect.affinity, req);
        if (0 != ret) {
            return ret;
        }
    }

    return ret;
} // end function set_requirement

/**
 * @brief       free memory of requirement structure.
 *
 * @param[out]   req          #1: requirement
 */
void
free_requirement(struct requirement *req)
{
    if (NULL == req) {
	return;
    }

    FREEUP(req->indicies);
    FREEUP(req->select);
    req->sizeof_select = 0;

    unsigned int i;
    if (NULL != req->select_array) {

        for (i=0; req->select_array[i]; i++) {
            FREEUP(req->select_array[i]);
        }

        FREEUP(req->select_array);
    }

    FREEUP(req->val);
    FREEUP(req->rusage_bit_map);

    gf_list_free(req->req_list, free_resrsv);

    return;
} // end function free_requirement

/**
 * @brief       merge the two requirement string.
 *
 * @param[in|out]   strtoreq     #1: keep content and merge another string to me
 * @param[in]       resreq       #2: merge this string
 * 
 * @retval      0             #1: succeed
 * @retval      -1            #2: failed, not enough memory or string has syntax error
 *
 * @note        select string:   copy from resreq to strtoreq,
 *                               add && if strtoreq has this section
 *              rusage string:   copy from resreq to strtoreq,
 *                               add , if strtoreq has this section
 *              order string:    copy from resreq to strtoreq,
 *                               add : if strtoreq has this section
 *              span string  :   copy from resreq to strtoreq if strtoreq has no this section
 *              affinity string: copy from resreq to strtoreq if strtoreq has no this section
 */
int
merge_requirement_string(char **strtoreq, char *resreq)
{
    char *strMergedReq;
    strMergedReq = copy_string(*strtoreq);

    char *strFromReq;
    strFromReq = copy_string(resreq);

    struct sections tosec, fromsec;
    if (0 != split_sections(strMergedReq, &tosec)) {
        FREEUP(strMergedReq);
        FREEUP(strFromReq);
        return -1;
    }

    if (0 != split_sections(strFromReq, &fromsec)) {
        FREEUP(strMergedReq);
        FREEUP(strFromReq);
        return -1;
    }

    *strtoreq = (char *)realloc(*strtoreq, strlen(*strtoreq)+strlen(resreq)+10);
    if (NULL == *strtoreq) {
        return -1;
    }

    *strtoreq[0] = '\0';
    if (NULL != tosec.select || NULL != fromsec.select) {

        strcat(*strtoreq, "select[");
        if (NULL != tosec.select) {
            strcat(*strtoreq, tosec.select);
            if (NULL != fromsec.select) {
                strcat(*strtoreq, "&&");
            }
        }

        if (NULL != fromsec.select) {
            strcat(*strtoreq, fromsec.select);
        }

        strcat(*strtoreq,"]");
    }

    if (NULL != tosec.rusage || NULL != fromsec.rusage) {

        strcat(*strtoreq, "rusage[");
        if (NULL != tosec.rusage) {
            strcat(*strtoreq, tosec.rusage);
            if (NULL != fromsec.rusage) {
                strcat(*strtoreq, ",");
            }
        }

        if (NULL != fromsec.rusage) {
            strcat(*strtoreq, fromsec.rusage);
        }

        strcat(*strtoreq, "]");
    }

    if (NULL != tosec.order || NULL != fromsec.order) {

        strcat(*strtoreq, "order[");
        if (NULL != tosec.order) {
            strcat(*strtoreq, tosec.order);
            if (NULL != fromsec.order) {
                strcat(*strtoreq, ":");
            }
        }

        if (NULL != fromsec.order) {
            strcat(*strtoreq, fromsec.order);
        }

        strcat(*strtoreq, "]");
    }

    if (NULL != tosec.span || NULL != fromsec.span) {

        strcat(*strtoreq, "span[");
        if (NULL != tosec.span) {
            strcat(*strtoreq, tosec.span);
        } else {
            strcat(*strtoreq, fromsec.span);
        }

        strcat(*strtoreq, "]");
    }

    if (NULL != tosec.affinity || NULL != fromsec.affinity) {

        strcat(*strtoreq, "affinity[");
        if (NULL != tosec.affinity) {
            strcat(*strtoreq, tosec.affinity);
        } else {
            strcat(*strtoreq, fromsec.affinity);
        }

        strcat(*strtoreq, "]");
    }

    FREEUP(strMergedReq);
    FREEUP(strFromReq);

    return 0;
} // end function merge_requirement_string

/* ------------------------------------------------
 *
 *  below are static functions used in this file
 *
 * ------------------------------------------------ */

/**
 * @brief       set default values for requirement.
 *
 * @param[out]  req           #1: requirement
 * @param[in]   info          #2: cluster resource table
 * @param[in]   options       #3: options for parsing the string
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, requirement string has syntax error
 *
 * @note        default type==any order[r1m:pg]
 */
static int
set_default_req(struct requirement *req, struct quickpoolInfo *info, int options)
{
    unsigned int i;

    if (options & REQ_TYPE) {
        strcpy(req->select, "expr [type \"eq\" \"local\"]");
    } else {
        strcpy(req->select, "expr [type \"eq\" \"any\"]");
    }

    req->num_order = 2;
    req->order[0] = R1M + 1;
    req->order[1] = PG + 1;
    req->val = (float *)calloc(info->num_resources, sizeof(float));
    req->indicies = (int *)calloc((info->num_index), sizeof(int));
    if (NULL == req->val || NULL == req->indicies) {
        free_requirement(req);
        return PARSE_ERROR_MEMORY;
    }

    for (i = 0; i < info->num_resources; i++) {
        req->val[i] = INFINIT_LOAD;
    }

    req->num_index = info->num_index;
    for(i = 0; i < req->num_index; i++) {
        req->indicies[i] = i;
    }

    req->rusage_bit_map = (int *)calloc(GET_INTNUM(info->num_resources), sizeof(int));
    if (NULL == req->rusage_bit_map) {
        free_requirement(req);
        return PARSE_ERROR_MEMORY;
    }

    req->duration = INFINIT_INT;
    req->decay = INFINIT_FLOAT;
    req->num_host = INFINIT_INT;
    req->max_num_host = INFINIT_INT;
    req->ptile = INFINIT_INT;
    req->options = 0;

    return 0;
} // end function set_default_req

static void
free_resrsv(void *resrsv)
{
    struct resrsv *freeResRsv = (struct resrsv *)resrsv;

    FREEUP(freeResRsv->bitmap);
    FREEUP(freeResRsv->val);
    FREEUP(freeResRsv);

    return;
} // end function free_resrsv

static cpubind_t
cmp_numatype(char *string)
{
    if (NULL == string) {
        return BIND_TYPE_CORE;
    }

    if (strcasecmp(string, "numa") == 0) {
        return BIND_TYPE_NUMA;
    } else if (strcasecmp(string, "socket") == 0) {
        return BIND_TYPE_SOCKET;
    } else if (strcasecmp(string, "core") == 0) {
        return BIND_TYPE_CORE;
    } else if (strcasecmp(string, "thread") == 0) {
        return BIND_TYPE_THREAD;
    }

    return BIND_TYPE_CORE;
} // end function cmp_numatype

static bool_t
isvalue_valid(char *value, struct quickpoolInfo *info, int nentry)
{
    if (0 == strcmp(value, WILDCARD_STR) || 0 == strcmp(value, LOCAL_STR)) {
        return TRUE;
    }

    unsigned int i;
    if (0 == strcmp(info->resource_table[nentry].name, "type")) {

        for(i=0; i<info->num_types; i++) {
            if (0 == strcmp(info->host_types[i], value)) {
                break;
            }
        }

        if (i == info->num_types) {
            return FALSE;
        }

        return TRUE;
    }

    if (0 == strcmp(info->resource_table[nentry].name, "model")) {

        for(i=0; i<info->num_models; i++) {
            if (0 == strcmp(info->host_models[i], value)) {
                break;
            }
        }

        if (i == info->num_models) {
            return FALSE;
        }

        return TRUE;
    }

    if (0 == strcmp(info->resource_table[nentry].name, "status")) {

        if (0 == strcmp(value,"ok") || 0 == strcmp(value,"busy")
            || 0 == strcmp(value,"closewin") || 0 == strcmp(value,"unavail")) {

            return TRUE;
        }

        return FALSE;
    }

    return TRUE;
} // end function isvalue_valid

/**
 * @brief       Convert the user specified select string into
 *              a string that TCL is able to process.
 *
 * @param[int]  select        #1: select string requirement
 * @param[in]   info          #2: cluster resource table
 * @param[out]  req           #1: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, cannot do the transfer
 *
 * @note        following string
 *                   "mem > 0 || swap < 10 || type == Linux"
 *              would be transfer to:
 *                   "expr mem()>0||swap()< 10||[type "eq" "Linux"]
 */
static int
transfer_select(char *select, struct quickpoolInfo *info, struct requirement *req)
{
    unsigned int len = strlen(select);
    char *sp = strip_spaces(req->select, FALSE);
    strcpy(sp, "expr ");

    unsigned int lenSrc = 0;
    unsigned int lenDst = strlen(sp);

    if (0 == strcmp(select, "-")) {
        char buffer[PATH_MAX*2+1];

        snprintf(buffer, PATH_MAX*2, "[type \"eq\" \"%s\"]", WILDCARD_STR);
	strcat(sp, buffer);
        lenDst += strlen(buffer);

        sp[lenDst] = '\0';
        req->options |= REQ_SELECT;

        return 0;
    }

    while (lenSrc < len) {
        if (lenDst >= (req->sizeof_select - MAXNAMELEN)) {
            return PARSE_BAD_EXP;
        }

        /* Skip spaces */
        if (' ' == select[lenSrc]) {
            lenSrc++;
            continue;
        }

        /* Copy reserved characters and numbers into target string */
        if (select[lenSrc] == '(' || select[lenSrc] == ')' || select[lenSrc] == '='
            || select[lenSrc] == '!' || select[lenSrc] == '>' || select[lenSrc] == '<'
            || select[lenSrc] == '|' || select[lenSrc] == '&' || select[lenSrc] == '+'
            || select[lenSrc] == '-' || select[lenSrc] == '*' || select[lenSrc] == '/'
            || select[lenSrc] == '.' || isdigit(select[lenSrc])) {

            sp[lenDst++] = select[lenSrc++];
            if (lenDst >= req->sizeof_select) {
                /* ensure we don't go beyond the bounds of the buffer */
               return(PARSE_BAD_VAL);
            }

            continue;
        }

        if (!isalpha(select[lenSrc])) {
            return (PARSE_BAD_EXP);
        }

        unsigned int lenRes = 0;
        char res[PATH_MAX];
        while (isalpha(select[lenSrc]) || isdigit(select[lenSrc])
               || IS_VALID_OTHER(select[lenSrc])) {

            res[lenRes++] = select[lenSrc++];
            if (lenRes >= PATH_MAX-1) {
                /* ensure we don't go beyond the bounds of the buffer */
                return(PARSE_BAD_VAL);
            }
        }

        res[lenRes] = '\0';

        int index;
        index = get_resource_index_fromhash(res);
        if (0 > index) {

            if (0 == strncmp("defined", res, strlen(res))) {

                while (' ' == select[lenSrc]) {
                    lenSrc++;
                }

                if ('(' != select[lenSrc]) {
                    return (PARSE_BAD_EXP);
                }

                lenRes = 0;
                lenSrc++;
                while (isalpha(select[lenSrc]) || isdigit(select[lenSrc])
                       || IS_VALID_OTHER(select[lenSrc])) {

                    res[lenRes++] = select[lenSrc++];
                    if (PATH_MAX-1 <= lenRes) {
                        /* string is too long */
                        return(PARSE_BAD_VAL);
                    }
                }

                res[lenRes] = '\0';
                index = get_resource_index_fromhash(res);
                if (0 > index) {
                    return PARSE_BAD_NAME;
                }

                char buffer[PATH_MAX*2];
                buffer[0] = '\0';
                if ((snprintf(buffer, PATH_MAX*2, "[%s \"%s\" ]", "defined",
                              info->resource_table[index].name) >= PATH_MAX*2)
                    || (strlen(buffer) + lenDst >= req->sizeof_select)) {
                    /* ensure we don't go beyond the bounds of the buffer */
                    return(PARSE_BAD_VAL);
                }

                sp[lenDst] = '\0';
                strcat(sp, buffer);
                lenDst += strlen(buffer);

                while (' ' == select[lenSrc]) {
                    lenSrc++;
                }

                if (')' != select[lenSrc]) {
                    return (PARSE_BAD_EXP);
                }
                lenSrc++;

                continue;
            }

            return PARSE_BAD_NAME;
        }

        const char *op;
        bool_t hasQuote;
        char val[PATH_MAX];
        switch(info->resource_table[index].value_type) {
        case TYPE_NUMERIC:
        case TYPE_BOOLEAN:
            strcat(res, "()");
            sp[lenDst] = '\0';

            strcat(sp, res);
            lenDst += strlen(res);

            break;
        case TYPE_STRING:
            // bypass spaces
            while (' ' == select[lenSrc]) {
                lenSrc++;
            }

            // Should have at least a operator and value
            if ('\0' == select[lenSrc] || '\0' == select[lenSrc+1]) {
                return(PARSE_BAD_EXP);
            }

            // Get the operator
            op = NULL;
            if ('=' == select[lenSrc] && '=' == select[lenSrc+1]) {
                op = "eq";
                lenSrc += 2;
            } else if ('!' == select[lenSrc] && '=' == select[lenSrc+1]) {
                op = "ne";
                lenSrc += 2;
            } else if ('>' == select[lenSrc] && '=' == select[lenSrc+1]) {
                op = "ge";
                lenSrc += 2;
            } else if ('<' == select[lenSrc] && '=' == select[lenSrc+1]) {
                op = "le";
                lenSrc += 2;
            } else if ('<' == select[lenSrc]) {
                op = "lt";
                lenSrc += 1;
            } else if ('>' == select[lenSrc]) {
                op = "gt";
                lenSrc += 1;
            } else { // not a valid operator
                return -1;
            }

            while (' ' == select[lenSrc]) {
                lenSrc++;
            }

            /* Get the value */
            if ('\'' == select[lenSrc]){
                hasQuote = TRUE;
                lenSrc++; // skip over quote
            } else {
                hasQuote = FALSE;
            }

            lenRes = 0;
            if (!hasQuote){
                while (isalpha(select[lenSrc]) || isdigit(select[lenSrc])
                      || IS_VALID_OTHER(select[lenSrc])) {

                    val[lenRes++] = select[lenSrc++];
                    if (PATH_MAX-1 <= lenRes) {
                        // string is too long
                        return(PARSE_BAD_VAL);
                    }
                }
            } else {
                while (select[lenSrc] && '\'' != select[lenSrc] && PATH_MAX > lenRes) {

                    val[lenRes++] = select[lenSrc++];
                    if (PATH_MAX <= lenRes) {
                        // string is too long
                        return (PARSE_BAD_VAL);
                    }
                }

                if ('\'' == select[lenSrc]) {
                    lenSrc++; // skip over quote
                }
            }

            val[lenRes] = '\0';
            if (0 == lenRes) { // not sepcify value
                return(PARSE_BAD_VAL);
            }

            /* Check if the value is valid for this resource */
            if (!isvalue_valid(val, info, index)) {
                return(PARSE_BAD_VAL);
            }

            /* Now combine them all together */
            char buffer[PATH_MAX*2];
            if ((snprintf(buffer, PATH_MAX * 2, "[%s \"%s\" \"%s\"]",
                          info->resource_table[index].name, op, val) >= PATH_MAX*2)
                || (strlen(buffer) + lenDst >= req->sizeof_select)) {

                // string is too long
                return(PARSE_BAD_VAL);
            }

            sp[lenDst] = '\0';
            strcat(sp, buffer);
            lenDst += strlen(buffer);

            break;
        default:
            break;
        }
    }

    sp[lenDst] = '\0';
    req->options |= REQ_SELECT;

    return 0;
} // end function transfer_select

/**
 * @brief       Parse select string and set to requirement.
 *
 * @param[in]   strreq        #1: select string
 * @param[in]   info          #2: cluster resource table
 * @param[in]   options       #3: options for parsing the string
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, select string has syntax error
 */
static int
set_select_req(char *strreq, struct quickpoolInfo *info, int options, struct requirement *req)
{
    char *sp = strreq;
    if (NULL == sp || 0 == strlen(sp)) { /* use default select */
        return 0;
    }

    unsigned int len = strlen(sp);
    char *strSelect = (char *)calloc(len+1, sizeof(char));
    if (NULL == strSelect) {
        return PARSE_ERROR_MEMORY;
    }

    unsigned int numComma=0;
    char *token;
    token = get_string_token(&sp, ",", strSelect, len+1);
    while (NULL != token) {
        numComma ++;
        len = strlen(sp);
        token = get_string_token(&sp, ",", strSelect, len+1);
    }

    char *strNewReq;
    if (1 < numComma) {

        req->select_array = (char **)calloc(numComma + 2, sizeof(char*));
        if (NULL == req->select_array) {

            FREEUP(strSelect);
            return(PARSE_ERROR_MEMORY);
        }

        strNewReq = (char *)calloc(strlen(strreq) + numComma * 4 - 1, sizeof(char));
        if (NULL == strNewReq) {

            FREEUP(strSelect);
            FREEUP(req->select_array);

            return (PARSE_ERROR_MEMORY);
        }
    } else {
        strNewReq = copy_string(strreq);
    }

    sp = strreq;
    len = strlen(sp);

    unsigned int lenResReq = len;

    if (1 < numComma) {

        numComma = 0;
        token = get_string_token(&sp, ",", strSelect, len+1);
        while (NULL != token) {
            struct requirement tokenReq;

            memset(&tokenReq, 0, sizeof(struct requirement));
            ALLOC_STRING(tokenReq.select, tokenReq.sizeof_select,
                         MAX(3*strlen(token) + 1, PATH_MAX + MAXNAMELEN));

            if (NULL == tokenReq.select) {

                FREEUP(strSelect);
                for (; numComma>0; numComma--) {
                    FREEUP(req->select_array[numComma]);
                }
                FREEUP(req->select_array);
                FREEUP(strNewReq);

                return PARSE_ERROR_MEMORY;
            }

            if (set_default_req(&tokenReq, info, options) < 0) {

                FREEUP(strSelect);
                for (; numComma>0; numComma--) {
                    FREEUP(req->select_array[numComma]);
                }
                FREEUP(req->select_array);
                FREEUP(strNewReq);

                return (PARSE_ERROR_MEMORY);
           }

            int ret;
            ret = set_select_req(token, info, options, &tokenReq);
            if (0 != ret) {

                FREEUP(strSelect);
                for (; numComma>0; numComma--) {
                    FREEUP(req->select_array[numComma]);
                }
                FREEUP(req->select_array);
                FREEUP(strNewReq);
                free_requirement(&tokenReq);

                return ret;
            }

            req->select_array[numComma] = copy_string(tokenReq.select);

            if (0 == numComma) {
                snprintf(strNewReq, lenResReq, "(%s)", token);
            } else {
                snprintf(strNewReq+strlen(strNewReq), lenResReq, "||(%s)", token);
            }

            free_requirement(&tokenReq);

            numComma ++;
            len = strlen(sp);
            token = get_string_token(&sp, ",", strSelect, len+1);
        }
    }
    FREEUP(strSelect);

    int ret;
    // transfer the select string to TCL style.
    ret = transfer_select(strNewReq, info, req);
    if (0 != ret) {

        req->select[0] = '\0';

        if (NULL != req->select_array) {
            for (; numComma>0; numComma--) {
                FREEUP(req->select_array[numComma]);
            }

            FREEUP(req->select_array);
        }

        FREEUP(strNewReq);

        return ret;
    }

    FREEUP(strNewReq);

    return 0;
} // end function set_select_req

/**
 * @brief       Parse order string and set to requirement.
 *
 * @param[in]   strreq        #1: order string
 * @param[in]   info          #2: cluster resource table
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, order string has syntax error
 */
static int
set_order_req(char *strreq, struct quickpoolInfo *info, struct requirement *req)
{
    unsigned int len = strlen(strreq);
    if (0 == len) {
        return 0;
    }

    char *strOrder = strip_spaces(strreq, FALSE);
    if (NULL == strOrder) {
        return 0;
    }

    req->num_order = 0;

    char *sp = strOrder;
    len = strlen(sp);

    char *order;
    order = (char *)calloc(len+1, sizeof(char));
    if (NULL == order) {
        return PARSE_ERROR_MEMORY;
    }

    char *token;
    while ((token = get_string_token(&strOrder, ":= ,", order, len+1)) != NULL) {
        bool_t negate = FALSE;

        if (token[0] == '-') {
            negate = TRUE;
            token++;
        }

        int index;
        index = get_resource_index_fromhash(token);
        if (0 > index || NA == info->resource_table[index].order_type) {
            FREEUP(order);
            return PARSE_BAD_NAME;
        }

        if (NUMBUILTIN < req->num_order) {
            break;
        }

        if (negate) {
            req->order[req->num_order] = -(index +1);
        } else {
            req->order[req->num_order] =  index + 1;
        }

        req->num_order ++;
        len = strlen(strOrder);
    }

    req->options |= REQ_ORDER;
    FREEUP(order);

    return 0;
} // end function set_order_req

/**
 * @brief       Parse filter string and set to requirement.
 *
 * @param[in]   strreq        #1: filter string
 * @param[in]   info          #2: cluster resource table
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, filter string has syntax error
 */
static int
set_filter_req(char *strreq, struct quickpoolInfo *info, struct requirement *req)
{
    unsigned int len = strlen(strreq);
    if (0 == len) {
        return 0;
    }

    char *strFilter = strip_spaces(strreq, FALSE);
    if (NULL == strFilter) {
        return 0;
    }

    char *filter;
    filter = (char *)calloc(len+1, sizeof(char));
    if (NULL == filter) {
        return PARSE_ERROR_MEMORY;
    }

    req->num_index = 0;
    char *token;
    while ((token = get_string_token(&strFilter, ":= ,", filter, len+1)) != NULL) {
        int index;

        index = get_resource_index_fromhash(token);
        if (0 > index) {

            FREEUP(filter);
            return(PARSE_BAD_FILTER);
        }

        if (!(info->resource_table[index].flags & RESOURCE_FLAG_DYNAMIC)) {
            FREEUP(filter);

            return(PARSE_BAD_FILTER);
        }

        if (info->resource_table[index].flags & RESOURCE_FLAG_SHARED) {
            FREEUP(filter);

            return (PARSE_BAD_FILTER);
        }

        req->indicies[req->num_index++] = index;
        len = strlen(strFilter);
    }

    req->options |= REQ_FILTER;
    FREEUP(filter);

    return (0);
} // end function set_filter_req

static int
key_index(char *key)
{
    unsigned int *indx;

    indx = (unsigned int *)gf_hash_find(shashKeyword, key);
    if (NULL == indx)
        return -1;

    return(int)(*indx);
}

static int
get_time_value(char **time, float *val)
{
    char *token, *cp, oneChar = '\0';
    char *tmp;
    unsigned int i = strlen(*time);

    tmp = (char *)calloc(i+1, sizeof(char));
    if (NULL == tmp) {
        return PARSE_ERROR_MEMORY;
    }

    token = get_string_token(time, ":= ,", tmp, i+1);
    if (NULL == token) {
        FREEUP(tmp);
        return -1;
    }

    cp = token;
    while (isdigit(*cp))
	cp++;

    if (*cp == 'm' || *cp == 'h' || *cp == 's') {
        oneChar = *cp;
        *cp = '\0';
    }

    if (!isnumber(token)) {
        FREEUP(tmp);
        return -1;
    }

    *val = atof(token);
    FREEUP(tmp);

    if (oneChar == 'h')
        *val *= ONEHOUR;
    else if ((oneChar == 'm') || (oneChar == '\0')){
        *val *= 60;
    }

    return 0;
}

static int
get_value(char **strval, float *val)
{
    char *token, *tmp;
    unsigned int i = strlen(*strval);

    tmp = (char *)calloc(i+1, sizeof(char));
    if (NULL == tmp) {
        return PARSE_ERROR_MEMORY;
    }

    token = get_string_token(strval, ":= ,", tmp, i+1);
    if (!isnumber(token)) {
        FREEUP(tmp);
        return -1;
    }

    *val = atof(token);
    FREEUP(tmp);

    return 0;
}

static int
get_rusage_list(const char *strrusage, LIST_T *rusagelist)
{
    LIST_PROXY_T *pxy;
    char *sp, *ss;
    sp = ss = copy_string(strrusage);
    if (NULL == strstr(ss, "||")) {

        pxy = (LIST_PROXY_T *)calloc(1, sizeof(struct list_proxy));
        if (NULL == pxy) {
            return PARSE_ERROR_MEMORY;
        }

        pxy->subject = (void *)ss;
        gf_list_insert(rusagelist, rusagelist, (LIST_T *)pxy);

        return LIST_NUM_ENTS(rusagelist);
    }

    char *p, *token;
    while (NULL != (p = strstr(ss, "||"))) {
        *p = 0;

        token = strip_spaces(ss, FALSE);
        if (NULL != token) {

            pxy = (LIST_PROXY_T *)calloc(1, sizeof(struct list_proxy));
            if (NULL == pxy) {
                return PARSE_ERROR_MEMORY;
            }

            pxy->subject = (void *)copy_string(token);
            gf_list_insert(rusagelist, rusagelist, (LIST_T *)pxy);
        }

        ss = p + 2;
    }

    token = strip_spaces(ss, FALSE);
    if (NULL != token) {

        pxy = (LIST_PROXY_T *)calloc(1, sizeof(struct list_proxy));
        if (NULL == pxy) {
            return PARSE_ERROR_MEMORY;
        }

        pxy->subject = (void *)copy_string(token);
        gf_list_insert(rusagelist, rusagelist, (LIST_T *)pxy);
    }

    FREEUP(sp);
    return LIST_NUM_ENTS(rusagelist);
} // end function get_rusage_list

/**
 * @brief       Parse rusage string and set to requirement.
 *
 * @param[in]   strreq        #1: rusage string
 * @param[in]   info          #2: cluster resource table
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, rusage string has syntax error
 */
static int
set_resusage_req(char *strreq, struct quickpoolInfo *info, struct requirement *req)
{
    unsigned int len = strlen(strreq);
    if (0 == len) {
        return 0;
    }

    char *strUsage = strip_spaces(strreq, FALSE);
    if (NULL == strUsage) {
        return 0;
    }

    req->req_list = gf_list_make("job rusage list");

    LIST_T *listRusage;
    listRusage = gf_list_make("string rusage list");

    get_rusage_list(strUsage, listRusage);

    int ret = 0;
    int *usageBitmap = NULL;
    float *val = NULL;

    LIST_ITERATOR_T iter;
    gf_listiterator_link(&iter, listRusage);

    unsigned int numUsage = 0;
    LIST_PROXY_T *pxy;
    for (pxy = (LIST_PROXY_T *)gf_listiterator_curentry(&iter);
         !gf_listiterator_isend(&iter);
         gf_listiterator_getnext(&iter, (LIST_T **)&pxy)) {

        char *subUsage;
        subUsage = (char *)pxy->subject;

        /* Allocate for each element of the list */
        usageBitmap = (int *)calloc(GET_INTNUM(info->num_resources), sizeof(int));
        val = (float *)calloc(info->num_resources, sizeof(float));
        if (NULL == usageBitmap || NULL == val) {

            ret = PARSE_ERROR_MEMORY;
            goto errret;
        }

        char *sp = subUsage;
        len = strlen(sp);
        char *resUsage = (char *)calloc(len+1, sizeof(char));
        if (NULL == resUsage) {

            ret = PARSE_ERROR_MEMORY;
            goto errret;
        }

        char *token;
        while ((token = get_string_token(&sp, ":= ,", resUsage, len+1)) != NULL) {

            if (token[0] == '-') {
                token++;
            }

            len = strlen(sp);

            float value;
            int index;
            index = key_index(token);
            if (0 < index) {
                if (index != KEY_DURATION && index != KEY_DECAY) {

                    FREEUP(resUsage);
                    ret = PARSE_BAD_NAME;

                    goto errret;
                }

                if (sp[0] == '=') {
                    int returnValue;
                    if (index == KEY_DURATION)
                        returnValue = get_time_value(&sp, &value);
                    else
                        returnValue = get_value(&sp, &value);

                    if (returnValue < 0 || value < 0.0) {
                        FREEUP(resUsage);
                        return PARSE_BAD_VAL;
                    }

                    if (index == KEY_DURATION) {
                        req->duration = value;
                    } else {
                        req->decay = value;
                    }

                    continue;
                }
            }

            index = get_resource_index_fromhash(token);
            if (0 > index) {

                FREEUP(resUsage);
                ret = PARSE_BAD_NAME;

                goto errret;
            }

            if (!(info->resource_table[index].flags & RESOURCE_FLAG_DYNAMIC)
                && (info->resource_table[index].value_type != TYPE_NUMERIC)) {

                if (sp[0] == '=') {
                    if (get_value(&sp, &value) < 0 || value < 0.0) {

                        FREEUP(resUsage);
                        ret = PARSE_BAD_VAL;
                        goto errret;
                    }
                }

                continue;
            }

            SET_BIT(index, usageBitmap);

            if (sp[0] == '=') {
                if (get_value(&sp, &value) < 0 || value < 0.0) {

                    FREEUP(resUsage);
                    ret = PARSE_BAD_VAL;
                    goto errret;
                }

                val[index] = value;
            }
        }

        FREEUP(resUsage);

        /* Save the current rusage block */
        struct resrsv *rsv;
        rsv = (struct resrsv *)calloc(1, sizeof(struct resrsv));
        if (NULL == rsv) {
            ret = PARSE_ERROR_MEMORY;
            goto errret;
        }

        rsv->bitmap = usageBitmap;
        rsv->val = val;
        gf_list_insert(req->req_list, req->req_list, (LIST_T *)rsv);

        if (0 == numUsage) {

            FREEUP(req->rusage_bit_map);
            FREEUP(req->val);

            /* Copy the values as later we free them separately */
            req->rusage_bit_map = (int *)calloc(GET_INTNUM(info->num_resources), sizeof(int));
            if (NULL == req->rusage_bit_map) {
                ret = PARSE_ERROR_MEMORY;
                goto errret;
            }

            memcpy(req->rusage_bit_map, usageBitmap, GET_INTNUM(info->num_resources) * sizeof(int));

            req->val = (float *)calloc(info->num_resources, sizeof(float));
            if (NULL == req->val) {
                ret = PARSE_ERROR_MEMORY;
                goto errret;
            }

            memcpy(req->val, rsv->val, info->num_resources * sizeof(float));
        }

        ++numUsage;
    } /* end for (pxy) */
    gf_list_free(listRusage, gf_free_proxy_string);

    req->options |= REQ_RUSAGE;

    return 0;

errret:

    FREEUP(usageBitmap);
    FREEUP(val);

    gf_list_free(listRusage, gf_free_proxy_string);
    gf_list_free(req->req_list, free_resrsv);
    req->req_list = NULL;

    return ret;
} // end function set_resusage_req

static int
get_span_values(char **strreq, int *val1, int *val2)
{
    *val1 = INFINIT_INT;
    *val2 = INFINIT_INT;

    char *strVal;
    unsigned int len;
    len = strlen(*strreq);
    strVal = (char *)calloc(len+1, sizeof(char));
    if (NULL == strVal) {
        return PARSE_ERROR_MEMORY;
    }

    char *token;
    token = get_string_token (strreq, ":= ,", strVal, len+1);
    if (NULL == token) {
        FREEUP(strVal);
        return 0;
    }

    len = strlen(token);
    if (0 == len) {
        FREEUP(strVal);
        return 0;
    }

    char *sp = token;
    while ('\0' != *sp && ',' != *sp && '/' != *sp) {
        sp ++;
    }

    char *strWord1=NULL, *strWord2=NULL;
    if ('\0' != *sp) {

        *sp = '\0';
        if (sp - token > 0) {
            strWord1 = token;
        }

        if (sp - token < len - 1) {
            strWord2 = ++sp;
        }
    } else {
        strWord1 = token;
    }

    if (NULL == strWord1 && NULL == strWord2) {
        FREEUP(strVal);
        return -1;
    }

    if (NULL != strWord1 && !isinteger(strWord1)) {
        FREEUP(strVal);
        return -1;
    }

    if (NULL != strWord2 && !isinteger(strWord2)) {
        FREEUP(strVal);
        return -1;
    }

    if (NULL != strWord1) {
        *val1 = atoi(strWord1);
    }

    if (NULL != strWord2) {
        *val2 = atoi(strWord2);
    }

    FREEUP(strVal);

    return 0;
} // end function get_span_values

/**
 * @brief       Parse span string and set to requirement.
 *
 * @param[in]   strreq        #1: span string
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, span string has syntax error
 */
static int
set_span_req(char *strreq, struct requirement *req)
{
    unsigned int len = strlen(strreq);
    if (0 == len) {
        return 0;
    }

    char *strSpan = strip_spaces(strreq, FALSE);
    if (NULL == strSpan) {
        return 0;
    }

    len = strlen(strSpan);
    char *span;
    span = (char *)calloc(len+1, sizeof(char));
    if (NULL == span) {
        return PARSE_ERROR_MEMORY;
    }

    char *token;
    while ((token = get_string_token(&strSpan, ":= ,", span, len+1)) != NULL) {
        if (token[0] == '-') {
            token++;
        }

        int index;
        index = key_index(token);
        if (0 <= index && index < KEY_HOSTS) {

            FREEUP(span);
            return(PARSE_BAD_NAME);
        }

        int val1, val2;
        if (get_span_values(&strSpan, &val1, &val2) < 0 || val1 <= 0.0 || val2 <= 0.0) {

            FREEUP(span);
            return PARSE_BAD_VAL;
        }

        switch (index) {
            case KEY_HOSTS:
                req->num_host = val1;
                req->max_num_host = val2;
                break;
            case KEY_PTILE:
                req->ptile = val1;
                if (val2 != INFINIT_INT) {

                    free(span);
                    return PARSE_BAD_VAL;
                }
                break;
            default:
                FREEUP(span);
                return(PARSE_BAD_NAME);
        }

        len = strlen(strSpan);
    }

    req->options |= REQ_SPAN;
    FREEUP(span);

    return (0);
}

/**
 * @brief       Parse affinity string and set to requirement.
 *
 * @param[in]   strreq        #1: affinity string
 * @param[out]  req           #4: requirement
 *
 * @retval      0             #1: succeed
 * @retval      < 0           #2: failed, affinity string has syntax error
 */
static int
set_affinity_req(char *strreq, struct requirement *req)
{
    unsigned int i, m;
    int typeFlag = 0;
    int sameFlag = FALSE, exclusiveFlag = FALSE;
    int exclusiveNum = 0, puNum = 0;

    if ((i = strlen(strreq)) == 0)
        return 0;

    for(m = 0; m < i; m++)
        if (strreq[m] != ' ')
            break;
    if (m == i)
        return 0;

    char *token, *tmp;
    tmp = (char *)calloc(i+1, sizeof(char));
    if (NULL == tmp) {
        return PARSE_ERROR_MEMORY;
    }

    while ((token = get_string_token(&strreq, ":", tmp, i+1)) != NULL) {
        if (token[0] == '-') {
            token++;
        }

        //affinity[core(5,same=numa):cpubind=numa:membind=localonly:distribute=pack]
        //affinity[core(5,same=numa,exclusive=(socket,injob))*2:cpubind=numa:membind=localonly:distribute=pack(numa=1)]
        //don't care pu_type * number and distribute
        char *tokenTmp, *tmp2;
        int size = 0, num = 0;
        size = strlen(token);
        tmp2 = (char *)calloc(size + 1, sizeof(char));
        if (NULL == tmp2) {
            FREEUP(tmp);
            return PARSE_ERROR_MEMORY;
        }
        typeFlag = 0;

        while ((tokenTmp = get_string_token(&token, "= ,*()", tmp2, size + 1)) != NULL) {
            if (tokenTmp[0] == '-') {
                tokenTmp++;
            }

            if (typeFlag & TYPE_PU) {
                if (sameFlag) {
                    req->same = cmp_numatype(tokenTmp);
                    if (req->bind_type <= req->same) {
                        return(PARSE_BAD_VAL);
                    }
                    sameFlag = FALSE;
                }
                if (exclusiveFlag) {
                    if (exclusiveNum == 0) {
                        if (req->exclusive.level != 0) {
                            FREEUP(tmp2);
                            FREEUP(tmp);
                            return(PARSE_BAD_NAME);
                        }
                        req->exclusive.level = cmp_numatype(tokenTmp);
                        if (req->exclusive.level == 0) {
                            FREEUP(tmp2);
                            FREEUP(tmp);
                            return(PARSE_BAD_NAME);
                        }
                         if (req->bind_type <= req->exclusive.level) {
                            FREEUP(tmp2);
                            FREEUP(tmp);
                            return(PARSE_BAD_VAL);
                        }                       
                        exclusiveNum++;
                    } else if (exclusiveNum == 1) {
                        if (req->exclusive.scope != 0) {
                            FREEUP(tmp2);
                            FREEUP(tmp);
                            return(PARSE_BAD_NAME);
                        }
                        if (strcasecmp(tokenTmp, "intask") == 0) {
                            req->exclusive.scope = SCOPE_INTASK;
                        } else if (strcasecmp(tokenTmp, "injob") == 0) {
                            req->exclusive.scope = SCOPE_INTJOB;
                        } else if (strcasecmp(tokenTmp, "alljobs") == 0) {
                            req->exclusive.scope = SCOPE_ALLJOBS;
                        } else {
                            FREEUP(tmp2);
                            FREEUP(tmp);
                            return(PARSE_BAD_NAME);
                        }
                        exclusiveFlag = FALSE;
                    }
                }

                if (sameFlag == FALSE && exclusiveFlag == FALSE && puNum == 0) {
                    //pu_type number must is the first data
                    if (0 != req->num_bind) {
                        FREEUP(tmp2);
                        FREEUP(tmp);
                        return(PARSE_BAD_NAME);
                    }

                    req->num_bind = atoi(tokenTmp);
                    puNum++;
                    if (0 >= req->num_bind) {
                        FREEUP(tmp2);
                        FREEUP(tmp);
                        return(PARSE_BAD_NAME);
                    }
                }

                if (strcasecmp("same", tokenTmp) == 0) {
                    sameFlag = TRUE;
                } else if (strcasecmp("exclusive", tokenTmp) == 0) {
                    exclusiveFlag = TRUE;
                }

            }

            if (typeFlag & TYPE_CPUBIND) {
                //avoid multiple type specifed 
                if (0 != req->cpubind_type) {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_NAME);
                }
                req->cpubind_type = cmp_numatype(tokenTmp);
                if (0 == req->cpubind_type) {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_NAME);
                }
                //the value of cpuBindType can not equal to bind_type
                if (req->cpubind_type == req->bind_type) {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_VAL);
                }
            }

            if (typeFlag & TYPE_MEMBIND) {
                //avoid multiple policy specifed 
                if (req->membind_type != 0) {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_NAME);
                }
                if (strcasecmp("localonly", tokenTmp) == 0) {
                    req->membind_type = MEMBIND_ONLY;
                } else if (strcasecmp("localprefer", tokenTmp) == 0) {
                    req->membind_type = MEMBIND_PREFER;
                } else {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_NAME);
                }
            }

            if (typeFlag & TYPE_DISTRIBUTE) {

            }                                          
            if (num == 0) {
                if (cmp_numatype(tokenTmp)) {
                    req->bind_type = cmp_numatype(tokenTmp);
                    typeFlag |= TYPE_PU;
                    num = 1;
                } else if (strcasecmp(tokenTmp, "cpubind") == 0) {
                    typeFlag |= TYPE_CPUBIND;
                    num = 1;
                } else if (strcasecmp(tokenTmp, "membind") == 0) {
                    typeFlag |= TYPE_MEMBIND;
                    num = 1;
                } else if (strcasecmp(tokenTmp, "distribute") == 0) {
                    typeFlag |= TYPE_DISTRIBUTE;
                    num = 1;
                } else {
                    FREEUP(tmp2);
                    FREEUP(tmp);
                    return(PARSE_BAD_NAME);
                }
            }

            size = strlen(token);

        }        
        i = strlen(strreq);
        FREEUP(tmp2);
    }
    req->options |= REQ_AFFINITY;
    FREEUP(tmp);

    return 0;
} // end function set_affinity_req

static int
split_sections(char *resreq, struct sections *sec)
{
    char *p1[NUMSECTION], *p2[NUMSECTION], *p;
    int i;
    for (i=0; i<NUMSECTION; i++) {

        p1[i] = strstr(resreq, keywords[i]);
        if (NULL != p1[i]) {
            p2[i] = strchr(p1[i], ']');
            if (NULL == p2[i]) {
                return -1;
            }
        }
    }

    if (NULL != p1[SELECT_SECT]) {
        sec->select = strchr(p1[SELECT_SECT], '[') + 1;
        *p2[SELECT_SECT] = '\0';
    } else {
        /* select string could be specified without the keyword
         * 'select', both -R select[xxx] and -R xxx are valid */
        p = resreq + strlen(resreq);
        for (i=1; i<NUMSECTION; i++) {
            if (p1[i] != NULL && p1[i] < p) {
                p = p1[i];
            }
        }

        if (p == resreq) {
            sec->select = NULL;
        } else {
            sec->select = resreq;
            *p='\0';
        }
    }

    if (NULL != p1[ORDER_SECT]) {
        sec->order = strchr(p1[ORDER_SECT]+1, '[') + 1;
        *p2[ORDER_SECT] = '\0';
    } else {
        sec->order = NULL;
    }

    if (NULL != p1[RUSAGE_SECT]) {
        sec->rusage = strchr(p1[RUSAGE_SECT]+1, '[') + 1;
        *p2[RUSAGE_SECT]='\0';
    } else {
        sec->rusage = NULL;
    }

    if (p1[FILTER_SECT] != NULL) {
        sec->filter = strchr(p1[FILTER_SECT] + 1,'[') + 1;
        *p2[FILTER_SECT] = '\0';
    } else {
       sec->filter = NULL;
    }

    if (NULL != p1[SPAN_SECT]) {
        sec->span = strchr(p1[SPAN_SECT]+1, '[') + 1;
        *p2[SPAN_SECT] = '\0';
    } else {
        sec->span = NULL;
    }

    if (NULL != p1[AFFINITY_SECT]) {
        sec->affinity = strchr(p1[AFFINITY_SECT]+1, '[') + 1;
        *p2[AFFINITY_SECT] = '\0';
    } else {
        sec->affinity = NULL;
    }

    return 0;
} // end function split_sections
